#ifndef PRTYPES_H
#define PRTYPES_H

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/remove.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/arithmetic/dec.hpp>
#include <list>

// One of the purpose of this application is to able to
// build itself automaticly.This is the reason behind
// the heavy use of macro.
// This file serve as a reference file to feed upon and 
// build whatever that is required

#ifndef JINC_MAX_ARG
#define JINC_MAX_ARG     10  // Controls max number of arg supported
#endif

#define CLASSDELM          "."

#define INT   5

// Helper Macros ...
/* #define ARGEXPR(n)        {(.*)\\} */
#define SELF(x) x
#define REPEAT_ENUM(z, n, data) (BOOST_PP_CAT(data, n))
#define REPEAT_REGXP(z, n, data) (data[n])
#define REPEAT_TRANSL(z, n, data)  ((BOOST_PP_CAT(SELF data, n)))
#define REMOVE_VOID(n ,t) BOOST_PP_SEQ_REMOVE(t, n)
#define SPC_MEMFN(z, n, data)			\
  ((BOOST_PP_CAT(SELF(data), n)))

/* #define SIGNREGX     -?   */
/* #define UNSIGNREGX   [^-] */
#define SIGNFNT(fnt)     BOOST_PP_CAT(s, fnt)
#define UNSIGNFNT(fnt)   BOOST_PP_CAT(un, fnt)

/* #define STARTREGX    \\(^ */
/* #define ENDREGX      $\\) */

#define PTRREGX(data)      data
#define PTRFNT(fnt)   BOOST_PP_CAT(p_, fnt)

// TODO: limit to JINC_MAX_ARG
// Make sure Schema file forces restriction ... for now
// Make list types
#define LISTREGX(data)   data 
#define LSTFNT(fnt)   BOOST_PP_CAT(a_, fnt)

#define LBOUND          0 // Min and Max number of digits allowed
#define HBOUND          BOOST_PP_SUB(JINC_MAX_ARG, 1)

/* #define ENCAP(r, data, t)          (STARTREGX t ENDREGX) */


// Transform basic types into their signed and unsigned equivalent
#define JNCSENUM(r, data, t)			\
  (BOOST_PP_CAT(S, t))(BOOST_PP_CAT(UN, t))
#define JNCSLOCAL(r, data, t)						\
  BOOST_PP_IF(BOOST_PP_SUB(2, BOOST_PP_SEQ_SIZE(t)), ((BOOST_PP_SEQ_HEAD(t))), ((BOOST_PP_CAT(s, BOOST_PP_SEQ_HEAD(t)))(signed SELF BOOST_PP_SEQ_TAIL(t)))((BOOST_PP_CAT(un, BOOST_PP_SEQ_HEAD(t)))(unsigned SELF BOOST_PP_SEQ_TAIL(t))))
#define JNCSREGEXP(r, data, t)			\
  (t[1])(t[2])
#define JNCSTRANSL(r, data, t)						\
  BOOST_PP_IF(BOOST_PP_SUB(2, BOOST_PP_SEQ_SIZE(t)), ((BOOST_PP_SEQ_HEAD(t))), ((BOOST_PP_CAT(s, BOOST_PP_SEQ_HEAD(t)))(SIGNFNT BOOST_PP_SEQ_TAIL(t)))((BOOST_PP_CAT(un, BOOST_PP_SEQ_HEAD(t)))(UNSIGNFNT BOOST_PP_SEQ_TAIL(t))))

// Transform basic and complex types into their pointer equivalent
#define JNCPENUM(r, data, t)			\
  (BOOST_PP_CAT(P_, t))
#define JNCPLOCAL(r, data, t)						\
  BOOST_PP_IF(BOOST_PP_SUB(2, BOOST_PP_SEQ_SIZE(t)), ((BOOST_PP_CAT(p_, BOOST_PP_SEQ_HEAD(t)))), ((BOOST_PP_CAT(p_, BOOST_PP_SEQ_HEAD(t)))(SELF BOOST_PP_SEQ_TAIL(t)*)))
#define JNCPREGEXP(r, data, t)			\
  (PTRREGX(t))
#define JNCPTRANSL(r, data, t)						\
  BOOST_PP_IF(BOOST_PP_SUB(2, BOOST_PP_SEQ_SIZE(t)), ((BOOST_PP_CAT(p_, BOOST_PP_SEQ_HEAD(t)))), ((BOOST_PP_CAT(p_, BOOST_PP_SEQ_HEAD(t)))(PTRFNT BOOST_PP_SEQ_TAIL(t))))

// Transform basic and complex types into their array equivalent
#define JNCLENUM(r, data, t)			\
  (BOOST_PP_CAT(A_, t))
#define JNCLLOCAL(r, data, t)						\
  BOOST_PP_IF(BOOST_PP_SUB(2, BOOST_PP_SEQ_SIZE(t)), ((BOOST_PP_CAT(a_, BOOST_PP_SEQ_HEAD(t)))), ((BOOST_PP_CAT(a_, BOOST_PP_SEQ_HEAD(t)))(SELF BOOST_PP_SEQ_TAIL(t)*)))
#define JNCLREGEXP(r, data, t)			\
  (LISTREGX(t))
#define JNCLTRANSL(r, data, t)				\
  BOOST_PP_IF(BOOST_PP_SUB(2, BOOST_PP_SEQ_SIZE(t)), ((BOOST_PP_CAT(a_, BOOST_PP_SEQ_HEAD(t)))), ((BOOST_PP_CAT(a_, BOOST_PP_SEQ_HEAD(t)))(LSTFNT BOOST_PP_SEQ_TAIL(t))))

// Types used throughout Jinc
#define ENUM1					\
  (JCHAR)(JSHORT)(JINT)(JLONG)

#define LOCAL1								\
  ((jchar)(char))((jshort)(short))((jint)(int))((jlong)(long))

#define REGEXP1								\
  (regex[0])(regex[1])(regex[2])(regex[3])

#define TRANSL1								\
  ((char)(toChar))((short)(toShort))((int)(toInt))((long)(toLong))


#define HOLD_ENUM2						\
  (JMFN)(JCMP)(JBOOL)(JVOID)(JDOUBLE)(JFLOAT)
#define ENUM2								\
  BOOST_PP_REPEAT(JINC_MAX_ARG, REPEAT_ENUM, BOOST_PP_SEQ_HEAD(HOLD_ENUM2)) BOOST_PP_SEQ_POP_FRONT(HOLD_ENUM2)

#define HOLD_LOCAL2							\
  ((jmfn))((jcmp))((jbool)(bool))((jvoid)(void))((jdouble)(double))((jfloat)(float))
#define LOCAL2								\
  BOOST_PP_REPEAT(JINC_MAX_ARG, REPEAT_TRANSL, BOOST_PP_SEQ_HEAD(HOLD_LOCAL2))BOOST_PP_SEQ_POP_FRONT(HOLD_LOCAL2)

#define HOLD_REGEXP2							\
  (regex)(regex[BOOST_PP_ADD(4, JINC_MAX_ARG)])(regex[BOOST_PP_ADD(1, BOOST_PP_ADD(4, JINC_MAX_ARG))])(regex[BOOST_PP_ADD(2, BOOST_PP_ADD(4, JINC_MAX_ARG))])(regex[BOOST_PP_ADD(3, BOOST_PP_ADD(4, JINC_MAX_ARG))])(regex[BOOST_PP_ADD(4, BOOST_PP_ADD(4, JINC_MAX_ARG))])
#define REGEXP2								\
  BOOST_PP_REPEAT_FROM_TO(4, BOOST_PP_ADD(4, JINC_MAX_ARG), REPEAT_REGXP, BOOST_PP_SEQ_HEAD(HOLD_REGEXP2))BOOST_PP_SEQ_POP_FRONT(HOLD_REGEXP2)

#define HOLD_TRANSL2							\
  ((mfn))((cmp))((bool)(toBool))((void))((double)(toDouble))((float)(toFloat))
#define TRANSL2								\
  BOOST_PP_REPEAT(JINC_MAX_ARG, REPEAT_TRANSL, BOOST_PP_SEQ_HEAD(HOLD_TRANSL2))BOOST_PP_SEQ_POP_FRONT(HOLD_TRANSL2)


#define ENUM3								\
  ENUM2 BOOST_PP_SEQ_FOR_EACH(JNCSENUM, ~, ENUM1)
#define LOCAL3								\
  LOCAL2 BOOST_PP_SEQ_FOR_EACH(JNCSLOCAL, ~, LOCAL1)
#define REGEXP3								\
  REGEXP2 BOOST_PP_SEQ_FOR_EACH(JNCSREGEXP, ~, REGEXP1)
#define TRANSL3								\
  TRANSL2 BOOST_PP_SEQ_FOR_EACH(JNCSTRANSL, ~, TRANSL1)


// Matrix defining relationship between different types used throughout Jinc
// Matrix should be similar to 
//  -------------------------------------------------
//  Type Index | Type   | Type Pattern   | Translation 
//  -------------------------------------------------
//     ENUM    | LOCAL  | REGEXP         | TRANSL
// --------- //
#define BENUM								\
  REMOVE_VOID(BOOST_PP_ADD(JINC_MAX_ARG, 2), ENUM2) ENUM1 BOOST_PP_SEQ_FOR_EACH(JNCSENUM, ~, ENUM1)
#define PENUM								\
  BOOST_PP_SEQ_FOR_EACH(JNCPENUM, ~, ENUM1) BOOST_PP_SEQ_FOR_EACH(JNCPENUM, ~, ENUM3) 
#define AENUM								\
  BOOST_PP_SEQ_FOR_EACH(JNCLENUM, ~, ENUM1) BOOST_PP_SEQ_FOR_EACH(JNCLENUM, ~, BOOST_PP_SEQ_FOR_EACH(JNCPENUM, ~, ENUM1)) BOOST_PP_SEQ_FOR_EACH(JNCLENUM, ~, ENUM3) BOOST_PP_SEQ_FOR_EACH(JNCLENUM, ~, BOOST_PP_SEQ_FOR_EACH(JNCPENUM, ~, ENUM3))
#define ENUM								\
  BENUM PENUM AENUM

// --------- //
#define BLOCAL								\
  REMOVE_VOID(BOOST_PP_ADD(JINC_MAX_ARG, 2), LOCAL2) LOCAL1 BOOST_PP_SEQ_FOR_EACH(JNCSLOCAL, ~, LOCAL1)
#define PLOCAL					\
  BOOST_PP_SEQ_FOR_EACH(JNCPLOCAL, ~, LOCAL1) BOOST_PP_SEQ_FOR_EACH(JNCPLOCAL, ~, LOCAL3) 
#define ALOCAL								\
  BOOST_PP_SEQ_FOR_EACH(JNCLLOCAL, ~, LOCAL1) BOOST_PP_SEQ_FOR_EACH(JNCLLOCAL, ~, BOOST_PP_SEQ_FOR_EACH(JNCPLOCAL, ~, LOCAL1)) BOOST_PP_SEQ_FOR_EACH(JNCLLOCAL, ~, LOCAL3) BOOST_PP_SEQ_FOR_EACH(JNCLLOCAL, ~, BOOST_PP_SEQ_FOR_EACH(JNCPLOCAL, ~, LOCAL3))
#define LOCAL					\
  BLOCAL PLOCAL ALOCAL

// ---------- //
#define BREGEXP								\
  REMOVE_VOID(BOOST_PP_ADD(JINC_MAX_ARG, 2), REGEXP2) REGEXP1 BOOST_PP_SEQ_FOR_EACH(JNCSREGEXP, ~, REGEXP1)
#define PREGEXP								\
  BOOST_PP_SEQ_FOR_EACH(JNCPREGEXP, ~, REGEXP1) BOOST_PP_SEQ_FOR_EACH(JNCPREGEXP, ~, REGEXP3) 
#define AREGEXP								\
  BOOST_PP_SEQ_FOR_EACH(JNCLREGEXP, ~, REGEXP1) BOOST_PP_SEQ_FOR_EACH(JNCLREGEXP, ~, BOOST_PP_SEQ_FOR_EACH(JNCPREGEXP, ~, REGEXP1)) BOOST_PP_SEQ_FOR_EACH(JNCLREGEXP, ~, REGEXP3) BOOST_PP_SEQ_FOR_EACH(JNCLREGEXP, ~, BOOST_PP_SEQ_FOR_EACH(JNCPREGEXP, ~, REGEXP3))
#define REGEXP					\
  BREGEXP PREGEXP AREGEXP

// ---------- //
#define BTRANSL								\
  REMOVE_VOID(BOOST_PP_ADD(JINC_MAX_ARG, 2), TRANSL2) TRANSL1 BOOST_PP_SEQ_FOR_EACH(JNCSTRANSL, ~, TRANSL1)
#define PTRANSL								\
  BOOST_PP_SEQ_FOR_EACH(JNCPTRANSL, ~, TRANSL1) BOOST_PP_SEQ_FOR_EACH(JNCPTRANSL, ~, TRANSL3) 
#define ATRANSL								\
  BOOST_PP_SEQ_FOR_EACH(JNCLTRANSL, ~, TRANSL1) BOOST_PP_SEQ_FOR_EACH(JNCLTRANSL, ~, BOOST_PP_SEQ_FOR_EACH(JNCPTRANSL, ~, TRANSL1)) BOOST_PP_SEQ_FOR_EACH(JNCLTRANSL, ~, TRANSL3) BOOST_PP_SEQ_FOR_EACH(JNCLTRANSL, ~, BOOST_PP_SEQ_FOR_EACH(JNCPTRANSL, ~, TRANSL3))
#define TRANSL					\
  BTRANSL PTRANSL ATRANSL

#define MAX_TYPE   BOOST_PP_SEQ_SIZE(LOCAL)

#endif
